home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 26 / develop Issue 26 code / Wide (64 bit) Library / Wide Library source / Wide.c next >
Encoding:
C/C++ Source or Header  |  1996-04-25  |  33.2 KB  |  1,413 lines  |  [TEXT/KAHL]

  1. /**********************************************************
  2.  
  3.     Wide.c
  4.  
  5.     Author:
  6.         Dale Semchishen, 1996
  7.  
  8.     Description:
  9.         A 64 bit integer library for the 680x0 and PowerPC processors
  10.  
  11.         While this library is self-initializing you can choose
  12.         to call WideInit() during application startup so that
  13.         the first time you call a math routine it does not incur
  14.         the extra time required for initialization.
  15.  
  16.         Most of the 64 bit routines in this library are available in
  17.         QuickDraw GX or on the PowerPC. On the 680x0 if you include
  18.         <GXTypes.h> or <GXMath.h> before "Wide.h" and compile this library,
  19.         the QuickDraw GX traps will be used instead of the routines
  20.         marked with "(gx)".
  21.  
  22.  
  23.     Global functions:
  24.         WideInit()            - Initialize the Wide library (optional)
  25.  
  26.         WideAdd()              - (gx) Add two 64 bit ints
  27.         WideAdd32()            -      Add 32 bits to a 64 bit int
  28.         WideAssign32()        -      Assign 32 bits to 64 bit int
  29.         WideBitShift()        -      Shift a 64 bit number
  30.         WideCompare()        - (gx) Compare two 64 bits ints
  31.         WideDivide()        - (gx) Divide 32 bit int into 64 bit int with a 32 bit result
  32.         WideMultiply()        - (gx) Multiply two 32 bits ints for a 64 bit result
  33.         WideNegate()        - (gx) Negative value of a 64 bit int
  34.         WideScale()            - (gx) Highest order nonzero bit in a 64 bit number
  35.         WideShift()            - (gx) Shift a 64 bit number and round up
  36.         WideSquareRoot()    - (gx) return 32 bit square root of an unsigned 64 bit number
  37.         WideSubtract32()    -      Subtract 32 bits from a 64 bit int
  38.         WideSubtract()        - (gx) Subtract a 64 bits int from a 64 bit int
  39.         WideToDecStr()        -      Convert 64 bit int to a SANE 'decimal' string
  40.         WideWideDivide()    - (gx) Divide 32 bit int into 64 bit int with a 64 bit result
  41.  
  42.     Note:
  43.          This library has been compiled under the following
  44.          development systems:
  45.              - Symantec C 68K 7.0.4
  46.              - CodeWarrior 6 Lite (68K and PPC)
  47.  
  48.  **********************************************************/
  49.  
  50.  
  51. #include "Wide.h"
  52.  
  53. #include <ToolUtils.h>
  54. #include <Gestalt.h>
  55.  
  56.  
  57. /*------------------- Local Constants --------------------*/
  58.  
  59. #define LONG_SIGN_BIT 0x80000000
  60.  
  61.  
  62. /*------------------- Local Variables --------------------*/
  63.  
  64. /* Is the Wide math library initialized ? */
  65. static short gWide_Initialized = false;
  66.  
  67. /* Are the MC680x0 64 bit multiply and divide instructions available ? */
  68. static short gWide_64instr = false;
  69.  
  70.  
  71. /*---------------- Compiler Dependancies -----------------*/
  72.  
  73. /* IF generating code for 680x0 CPUs */
  74. #if GENERATING68K
  75.  
  76. /* IF MetroWorks compiler */
  77. #ifdef __MWERKS__
  78.  
  79. typedef extended80   Extended_80;
  80. typedef DecForm      decform;
  81. #define FIXEDDECIMAL FixedDecimal
  82.  
  83. #define ASM_FUNC_HEAD    asm
  84. #define ASM_BEGIN        LINK A6,#0
  85. #define ASM_END            UNLK A6
  86. #define ASM_FUNC_TAIL     RTS
  87.  
  88. #define WIDE_HI 0
  89. #define WIDE_LO 4
  90.  
  91. /* ELSE IF Symantec C */
  92. #elif THINK_C
  93.  
  94. typedef extended    Extended_80;
  95.  
  96. #define ASM_FUNC_HEAD
  97. #define ASM_BEGIN        asm{
  98. #define ASM_END            }
  99. #define ASM_FUNC_TAIL
  100.  
  101. #define WIDE_LO wide.lo
  102. #define WIDE_HI wide.hi
  103.  
  104. #else
  105. #error "Wide library has not been ported to this 68K environment"
  106. #endif
  107.  
  108. /* ELSE generating code for PowerPC */
  109. #else
  110.  
  111. /* IF the MetroWorks compiler */
  112. #ifdef __MWERKS__
  113.  
  114. typedef struct _extended80  Extended_80;
  115.  
  116. #else
  117. #error "Wide library has not been ported to this PowerPC environment"
  118. #endif
  119.  
  120. #endif
  121.  
  122.  
  123.  
  124. /**********************************************************
  125.  
  126.     WideInit - Initialize the Wide math library
  127.  
  128.     Description:
  129.         This routine will set the internal flags used by the
  130.         Wide math library. These flags tested by the multiply
  131.         and divide functions in order to determine if there
  132.         are 680x0 64 bit math instructions that can be used
  133.         instead of a software algorithm.
  134.  
  135.         While this library is self-initializing you can choose
  136.         to call WideInit() during application startup so that
  137.         the first time you call a math routine it does not incur
  138.         the extra time required for initialization.
  139.  
  140.     Return value:
  141.         none
  142.  
  143. **********************************************************/
  144. void WideInit( void )
  145. {
  146.     long   processor_type;
  147.     
  148.  
  149.     /* IF able to determine processor type */
  150.     if( Gestalt( gestaltProcessorType, &processor_type ) == noErr )
  151.     {
  152.         processor_type &= 0xFFFF;
  153.     }
  154.     /* ELSE assume we have the oldest CPU */
  155.     else
  156.     {
  157.         processor_type = gestalt68000;
  158.     }
  159.  
  160.     /* 64 bit mult and div instructions available if CPU is 68020 to 68040 */
  161.     gWide_64instr = (processor_type >= gestalt68020) &&
  162.                     (processor_type <= gestalt68040);
  163.  
  164.     gWide_Initialized = true;
  165. }
  166.  
  167.  
  168.  
  169. /**********************************************************
  170.  
  171.     WideAssign32 - Assign 32 bits to 64 bit int
  172.  
  173.     Description:
  174.         This routine will assign a signed 32 bit integer to
  175.         a signed 64 bit integer
  176.  
  177.     Return value:
  178.         the target pointer passed into this function
  179.  
  180. **********************************************************/
  181. wide *WideAssign32
  182. (
  183.     wide    *target_ptr,    /* out: 64 bits to be assigned */
  184.     long     value            /* in:  assignment value */
  185. )
  186. {
  187.     /* initialize Wide library if not already done */
  188.     if( !gWide_Initialized ) WideInit();
  189.  
  190.     target_ptr->lo = value;
  191.     target_ptr->hi = (value >= 0) ? 0: -1;
  192.  
  193.     return( target_ptr );
  194. }
  195.  
  196.  
  197.  
  198. /**********************************************************
  199.  
  200.     WideAdd32 - Add 32 bits to a 64 bit int
  201.  
  202.     Description:
  203.         This routine will add a signed 32 bit integer to
  204.         a signed 64 bit integer
  205.  
  206.     Return value:
  207.         the target pointer passed into this function
  208.  
  209. **********************************************************/
  210. wide *WideAdd32
  211. (
  212.     wide    *target_ptr,    /* out: 64 bits to be added to */
  213.     long     value          /* in:  addition value */
  214. )
  215. {
  216.     wide    temp;
  217.  
  218.  
  219.     /* note: library initialization check done by WideAdd() */
  220.  
  221.     /* convert value to 64 bits */
  222.     temp.lo = value;
  223.     temp.hi = (value >= 0) ? 0: -1;
  224.  
  225.     /* do the add */
  226.     return( WideAdd( target_ptr, &temp ) );
  227. }
  228.  
  229.  
  230.  
  231. /**********************************************************
  232.  
  233.     WideSubtract32 - Subtract 32 bits from a 64 bit int
  234.  
  235.     Description:
  236.         This routine will subtract a signed 32 bit integer from
  237.         a signed 64 bit integer
  238.  
  239.     Return value:
  240.         the target pointer passed into this function
  241.  
  242. **********************************************************/
  243. wide *WideSubtract32
  244. (
  245.     wide    *target_ptr,    /* out: 64 bits to be subtracted from */
  246.     long     value          /* in:  subtraction value */
  247. )
  248. {
  249.     wide    temp;
  250.  
  251.  
  252.     /* note: library initialization check done by WideSubtract() */
  253.  
  254.     /* convert value to 64 bits */
  255.     temp.lo = value;
  256.     temp.hi = (value >= 0) ? 0: -1;
  257.  
  258.     /* do the subtract */
  259.     return( WideSubtract( target_ptr, &temp ) );
  260. }
  261.  
  262.  
  263.  
  264. /* IF QuickDraw GX is not included */
  265. #ifndef __GXMATH__
  266.  
  267. /**********************************************************
  268.  
  269.     WideScale - (gx) Highest order nonzero bit in a 64 bit number
  270.  
  271.     Description:
  272.         This routine will return the bit number of the
  273.         highest-order nonzero bit in a 64 bit number.
  274.  
  275.     Return value:
  276.         0 to 63 (bit position of highest-order nonzero bit)
  277.         or
  278.         -1 if all bits are zero
  279.  
  280. **********************************************************/
  281. short WideScale
  282. (
  283.     const wide  *bigint_ptr     /* in: 64 bits to test */
  284. )
  285. {
  286. register short           rv;
  287. register long           accum_hi;
  288. register unsigned long accum_lo;
  289.  
  290.  
  291.     /* initialize Wide library if not already done */
  292.     if( !gWide_Initialized ) WideInit();
  293.  
  294.     rv = 63;
  295.     accum_hi = bigint_ptr->hi;
  296.     accum_lo = bigint_ptr->lo;
  297.  
  298.     /* WHILE we have not found the left-most 1 bit */
  299.     while( ((accum_hi & LONG_SIGN_BIT) == 0) && (rv >= 0) )
  300.     {
  301.         --rv;
  302.  
  303.         /* shift 64 bits left once */
  304.         accum_hi <<= 1;
  305.         if( accum_lo & LONG_SIGN_BIT )
  306.         {
  307.             accum_hi |= 1;
  308.         }
  309.         accum_lo <<= 1;
  310.     }
  311.  
  312.     return( rv );
  313. }
  314. #endif
  315.  
  316.  
  317.  
  318. /**********************************************************
  319.  
  320.     Wide_ToExtended - internal 68K routine
  321.     Wide_ToDouble   - internal PPC routine
  322.  
  323.     Description:
  324.         An internal routine that converts a signed
  325.         'wide' value to a signed 'extended' or Double value.
  326.  
  327.     Return value:
  328.         none
  329.  
  330. **********************************************************/
  331.  
  332. /* IF generating code for 680x0 CPUs */
  333. #if GENERATING68K
  334. static void Wide_ToExtended
  335. (
  336.     Extended_80 *target_ptr,    /* out: extended number */
  337.     const  wide *source_ptr     /* in:  64 bits to convert */
  338. )
  339. {
  340.     short    sign_bit;
  341.     short    left_most;
  342.     wide    work_int = *source_ptr;
  343.     struct _extended80 *outp = (struct _extended80 *) target_ptr;
  344.  
  345.  
  346.     /* IF negative */
  347.     sign_bit = (work_int.hi & LONG_SIGN_BIT) >> 16;
  348.     if( sign_bit )
  349.     {
  350.         /* convert number to positive */
  351.         WideNegate( &work_int );
  352.     }
  353.  
  354.     /* determine left-most 1 bit */
  355.     left_most = WideScale( &work_int );
  356.  
  357.     /* IF there are no 1 bits */
  358.     if( left_most < 0 )
  359.     {
  360.         /* the answer is zero */
  361.         outp->exp = 0;
  362.         outp->man[0] = 0;
  363.         outp->man[1] = 0;
  364.         outp->man[2] = 0;
  365.         outp->man[3] = 0;
  366.     }
  367.     /* ELSE a non-zero number */
  368.     else
  369.     {
  370.         /* left justify the bits */
  371.         WideBitShift( &work_int, -(63 - left_most) );
  372.  
  373.         /* output the 'extended' number */
  374.         outp->exp = sign_bit | (0x3FFF + left_most);
  375.         (*(long *) &outp->man[0]) = work_int.hi;
  376.         (*(long *) &outp->man[2]) = work_int.lo;
  377.     }
  378. }
  379.  
  380. /* ELSE generating code for PowerPC */
  381. #else
  382. static void Wide_ToDouble
  383. (
  384.     double_t    *target_ptr,    /* out: double number */
  385.     const  wide *source_ptr     /* in:  64 bits to convert */
  386. )
  387. {
  388.     long            left_most;
  389.     unsigned long    sign_bit;
  390.     wide    work_int = *source_ptr;
  391.     union
  392.     {
  393.         double_t        dbl_num;
  394.         unsigned long    half[2];
  395.     } work;
  396.  
  397.  
  398.     /* IF negative */
  399.     sign_bit = work_int.hi & LONG_SIGN_BIT;
  400.     if( sign_bit )
  401.     {
  402.         /* convert number to positive */
  403.         WideNegate( &work_int );
  404.     }
  405.  
  406.     /* determine left-most 1 bit */
  407.     left_most = WideScale( &work_int );
  408.  
  409.     /* IF there are no 1 bits */
  410.     if( left_most < 0 )
  411.     {
  412.         /* build the double number */
  413.         work.half[0] = 0;
  414.         work.half[1] = 0;
  415.     }
  416.     /* ELSE a non-zero number */
  417.     else
  418.     {
  419.         /* left justify the bits and toss the msb (so we normalize the fraction) */
  420.         WideBitShift( &work_int, -(64 - left_most) );
  421.  
  422.         /* build the double number */
  423.         work.half[0] = sign_bit | ((0x3FF + left_most) << 20);
  424.         work.half[0] |= (work_int.hi >> 12) & 0x000FFFFF;
  425.         work.half[1] = (work_int.hi << 20) | ((work_int.lo >> 12) & 0x000FFFFF);
  426.     }
  427.  
  428.     /* output the result */
  429.     *target_ptr = work.dbl_num;
  430. }
  431. #endif
  432.  
  433.  
  434.  
  435. /**********************************************************
  436.  
  437.     WideToDecStr - Convert 64 bit int to a SANE 'decimal' string
  438.  
  439.     Description:
  440.         This routine will convert a signed 64 bit integer
  441.         to the 'decimal' type string supported by the SANE library.
  442.  
  443.     Return value:
  444.         none
  445.  
  446. **********************************************************/
  447. void WideToDecStr
  448. (
  449.           decimal   *decstr_ptr,    /* out: 'decimal' output string */
  450.     const wide        *source_ptr     /* in:  64 bits to convert */
  451. )
  452. /* IF generating code for 680x0 CPUs */
  453. #if GENERATING68K
  454. {
  455.     decform         format;
  456.     Extended_80     ext_number;
  457.  
  458.  
  459.     /* initialize Wide library if not already done */
  460.     if( !gWide_Initialized ) WideInit();
  461.  
  462.     /* convert 'wide' number to 'extended' format */
  463.     Wide_ToExtended( &ext_number, source_ptr );
  464.  
  465.     /* define how num2dec() will generate the string */
  466.     format.style = FIXEDDECIMAL;
  467.     format.digits = 0;
  468.  
  469.     /* pre-initialize to zero because for Symantec SANE (possibly   */
  470.     /* others) decimal.exp will be uninitialized if ext_number is 0 */
  471.     decstr_ptr->exp = 0;
  472.  
  473.     /* IF 68K MetroWorks compiler, the second parameter of num2dec()
  474.        is a pointer instead of a value as defined in PowerPC Numerics */
  475. #ifdef __MWERKS__
  476.     /* generate the 'decimal' string */
  477.     Num2Dec( &format, &ext_number, decstr_ptr );
  478. #else
  479.     /* generate the 'decimal' string */
  480.     num2dec( &format, ext_number, decstr_ptr );
  481. #endif
  482. }
  483. /* ELSE generating code for PowerPC */
  484. #else
  485. {
  486.     decform     format;
  487.     double_t    dbl_number;
  488.  
  489.  
  490.     /* initialize Wide library if not already done */
  491.     if( !gWide_Initialized ) WideInit();
  492.  
  493.     /* convert 'wide' number to 'double' format */
  494.     Wide_ToDouble( &dbl_number, source_ptr );
  495.  
  496.     format.style = FIXEDDECIMAL;
  497.     format.digits = 0;
  498.  
  499.     /* generate the 'decimal' string */
  500.     num2dec( &format, dbl_number, decstr_ptr );
  501. }
  502. #endif
  503.  
  504.  
  505.  
  506. /* IF generating code for 680x0 CPUs */
  507. #if GENERATING68K
  508.  
  509. /**********************************************************
  510.  
  511.     WideBitShift - Shift a 64 bit number
  512.  
  513.     Description:
  514.         This routine will perform an arithmetic shift on a
  515.         64 bit number.
  516.  
  517.         If the shift amount is 0, then the resulting value
  518.         will be the same as the input value.
  519.  
  520.         When the shift amount is positive, the 64 bit number
  521.         will be shifted to the right (decreasing magnitude). 
  522.  
  523.         When the shift amount is negative, the 64 bit number
  524.         will be shifted to the left (decreasing increasing). 
  525.  
  526.     Return value:
  527.         the target pointer passed into this function
  528.  
  529. **********************************************************/
  530. wide *WideBitShift
  531. (
  532.     wide    *target_ptr,    /* in/out: 64 bits to be shifted */
  533.     short       amount      /* in:     shift amount (+ right, - left) */
  534. )
  535. {
  536. register long hi;
  537. register unsigned long lo;
  538. register short shift_amount;
  539.  
  540.  
  541.     /* initialize Wide library if not already done */
  542.     if( !gWide_Initialized ) WideInit();
  543.  
  544.     hi = target_ptr->hi;
  545.     lo = target_ptr->lo;
  546.     shift_amount = amount;
  547.  
  548.     /* IF shifting right more than 31 bits */
  549.     if( shift_amount > 31 )
  550.     {
  551.         lo = hi >> (shift_amount - 32);
  552.         hi = 0;
  553.     }
  554.     /* ELSE IF shifting right 1-31 bits */
  555.     else if( shift_amount > 0 )
  556.     {
  557.         lo = (lo >> shift_amount) | (hi << (32 - shift_amount));
  558.         hi >>= shift_amount;
  559.     }
  560.     /* ELSE IF shifting left more than 31 bits */
  561.     else if( shift_amount < -31 )
  562.     {
  563.         hi = lo << -(shift_amount + 32);
  564.         lo = 0;
  565.     }
  566.     /* ELSE IF shifting left 1-31 bits */
  567.     else if( shift_amount < 0 )
  568.     {
  569.         hi = (hi << -shift_amount) | (lo >> (32 + shift_amount));
  570.         lo <<= -shift_amount;
  571.     }
  572.  
  573.     target_ptr->hi = hi;
  574.     target_ptr->lo = lo;
  575.  
  576.     return( target_ptr );
  577. }
  578.  
  579.  
  580.  
  581. /* IF QuickDraw GX is not included */
  582. #ifndef __GXMATH__
  583.  
  584.  
  585. /**********************************************************
  586.  
  587.     WideAdd - (gx) Add two 64 bit ints
  588.  
  589.     Description:
  590.         This routine will add a signed 64 bit integer to
  591.         a signed 64 bit integer.
  592.  
  593.         The source integer will be added to the target integer.
  594.  
  595.     Return value:
  596.         the target pointer passed into this function
  597.  
  598. **********************************************************/
  599. wide *WideAdd
  600. (
  601.           wide  *target_ptr,    /* out: 64 bits to be added to */
  602.     const wide  *source_ptr        /* in:  addition value */
  603. )
  604. {
  605. register unsigned long accum_lo;
  606. register long           accum_hi;
  607. register wide *destp;
  608.  
  609.  
  610.     /* initialize Wide library if not already done */
  611.     if( !gWide_Initialized ) WideInit();
  612.  
  613.     /* perform a partial add */
  614.     destp = target_ptr;
  615.     accum_lo = destp->lo + source_ptr->lo;
  616.     accum_hi = destp->hi + source_ptr->hi;
  617.  
  618.     /* IF the low long has overflowed */
  619.     if( (accum_lo < destp->lo) ||
  620.         (accum_lo < source_ptr->lo) )
  621.     {
  622.         /* propagate the carry */
  623.         accum_hi += 1;
  624.     }
  625.  
  626.     destp->hi = accum_hi;
  627.     destp->lo = accum_lo;
  628.  
  629.     return( destp );
  630. }
  631.  
  632.  
  633.  
  634.  
  635. /**********************************************************
  636.  
  637.     WideCompare - (gx) Compare two 64 bits ints
  638.  
  639.     Description:
  640.         This routine will compare a signed 64 bit integer
  641.         with a signed 64 bit integer.
  642.  
  643.     Return value:
  644.         1  if target number is greater than the source number
  645.         0  if the two numbers are equal
  646.        -1  if target is less than the source number
  647.         
  648. **********************************************************/
  649. short WideCompare
  650. (
  651.     const wide    *target_ptr,    /* in: target number */
  652.     const wide    *source_ptr     /* in: source number */
  653. )
  654. {
  655.     wide  work;
  656.  
  657.  
  658.     /* note: library initialization check done by WideSubtract() */
  659.  
  660.     work = *target_ptr;
  661.     WideSubtract( &work, source_ptr );
  662.  
  663.     if( (work.hi == 0) && (work.lo == 0) )
  664.     {
  665.         return( 0 );
  666.     }
  667.  
  668.     if( work.hi < 0 )
  669.     {
  670.         return( -1 );
  671.     }
  672.  
  673.     return( 1 );
  674. }
  675.  
  676.  
  677.  
  678. /**********************************************************
  679.  
  680.     Wide_DivideU - internal routine
  681.  
  682.     Description:
  683.         A 680x0 assembly language routine that performs an
  684.         performs an unsigned 64 bit division.
  685.  
  686.         The algorithm is a binary version of the paper and
  687.         pencil method of division you learned in school.
  688.         It will loop once for each bit in the sizeof the
  689.         divisor (which is 32).
  690.  
  691.     Return value:
  692.         none
  693.  
  694. **********************************************************/
  695. ASM_FUNC_HEAD static void Wide_DivideU
  696. (
  697.     wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  698.     long     divisor,            /* in:      value to divide by */
  699.     long    *remainder_ptr        /* out:     the remainder of the division */
  700. )
  701. {
  702. #define DIVIDEND_PTR   8
  703. #define DIVISOR       12
  704. #define REMAINDER_PTR 16
  705.  
  706. ASM_BEGIN
  707.         MOVEM.L D2-D7,-(SP)            // save work registers
  708.         CLR.L    D0                    //
  709.         CLR.L    D1                    // D0-D1 is the quotient accumulator
  710.         MOVE.L    DIVIDEND_PTR(A6),A0    //
  711.         MOVE.L    WIDE_HI(A0),D2      //
  712.         MOVE.L    WIDE_LO(A0),D3      // D2-D3 is the remainder accumulator
  713.         CLR.L    D4                    //
  714.         MOVE.L    D2,D5                // D5 = copy of dividend.hi
  715.         MOVE.L    DIVISOR(A6),D6        // D6 = copy of divisor
  716.  
  717.         MOVEQ.L #31,D7                // FOR number of bits in divisor (see @div99:)
  718. @divloop:
  719.         LSL.L   #1,D0               // shift quotient.hi accumulator left once
  720.         LSL.L   #1,D1               // shift quotient.lo accumulator left once
  721.         LSL.L    #1,D4                //
  722.         LSL.L   #1,D3               // shift remainder accumulator left once
  723.         BCC        @div29                // IF CC, a zero bit shifted out
  724.         LSL.L   #1,D2               //
  725.         BSET    #0,D2                //
  726.         BRA        @div30
  727. @div29:
  728.         LSL.L   #1,D2               //
  729. @div30:
  730.         SUB.L    D6,D2                // remainder -= divisor
  731.         BCS        @div50                // IF CS, remainder is negative
  732.         BSET    #0,D1                // quotient.lo |= 1
  733.         BRA.S    @div77                //
  734. @div50:
  735.         ADD.L    D6,D2                // remainder += divisor
  736. @div77:
  737.         BTST    D7,D5                //
  738.         BEQ        @div90                // IF EQ, bit not set in dividend.hi
  739.         BSET    #0,D4                //
  740. @div90:
  741.         CMP.L    D6,D4                //
  742.         BCS        @div99                // IF CS, divisor < D4
  743.         SUB.L    D6,D4                // D4 -= divisor
  744.         BSET    #0,D0                // quotient.hi |= 1
  745. @div99:
  746.         DBF        D7,@divloop            // loop until D7 == -1
  747.  
  748.         MOVE.L    DIVIDEND_PTR(A6),A0 // output the remainder
  749.         MOVE.L    D0,WIDE_HI(A0)      //
  750.         MOVE.L    D1,WIDE_LO(A0)      //
  751.         MOVE.L    REMAINDER_PTR(A6),A0// output the remainder
  752.         MOVE.L    D2,(A0)             //
  753.         MOVEM.L (SP)+,D2-D7            // restore work registers
  754. ASM_END
  755. ASM_FUNC_TAIL
  756. }
  757.  
  758.  
  759.  
  760. /**********************************************************
  761.  
  762.     Wide_DivideS - internal routine
  763.  
  764.     Description:
  765.         An internal routine that will divide a signed 32 bit
  766.         number into a signed 64 bit number and produce a
  767.         signed 64 bit result.
  768.  
  769.     Return value:
  770.         none
  771.  
  772. **********************************************************/
  773. static void Wide_DivideS
  774. (
  775.     wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  776.     long     divisor,            /* in:      value to divide by */
  777.     long    *remainder_ptr        /* out:     the remainder of the division */
  778. )
  779. {
  780.     wide    dividend;
  781.     long    remainder;
  782.     long    negative_result;
  783.  
  784.  
  785.     dividend = *dividend_ptr;
  786.     
  787.     /* determine if result of the divide will be positive or negative */
  788.     negative_result = (dividend_ptr->hi & LONG_SIGN_BIT) ^ (divisor & LONG_SIGN_BIT);
  789.  
  790.     /* IF dividend is negative */
  791.     if( dividend_ptr->hi < 0 )
  792.     {
  793.         /* divide algorithm is unsigned */
  794.         WideNegate( ÷nd );;
  795.     }
  796.  
  797.     /* IF divisor is negative */
  798.     if( divisor < 0 )
  799.     {
  800.         /* divide algorithm is unsigned */
  801.         divisor = -divisor;
  802.     }
  803.  
  804.     /* perform an unsigned division */
  805.     Wide_DivideU( ÷nd, divisor, &remainder );
  806.  
  807.     /* IF negative dividend */
  808.     if( dividend_ptr->hi < 0 )
  809.     {
  810.         *remainder_ptr = -remainder;
  811.     }
  812.     else
  813.     {
  814.         *remainder_ptr = remainder;
  815.     }
  816.  
  817.     /* IF negative quotient */
  818.     if( negative_result )
  819.     {
  820.         /* correct the sign */
  821.         WideNegate( ÷nd );
  822.     }
  823.  
  824.     *dividend_ptr = dividend;
  825. }
  826.  
  827.  
  828.  
  829.  
  830. /**********************************************************
  831.  
  832.     WideWideDivide - (gx) Divide 32 bit int into 64 bit int with a 64 bit result
  833.  
  834.     Description:
  835.         This routine will divide a signed 32 bit integer into
  836.         a signed 64 bit integer and return a signed 64 bit quotient
  837.         and a 32 bit remainder.
  838.  
  839.         When this function returns the dividend will be replaced
  840.         by the quotient
  841.  
  842.         If the divisor is zero, then the quotient will be set to the
  843.         largest positive or negative number, as appropriate.
  844.         And the remainder will be gxNegativeInfinity.
  845.  
  846.         If the 'remainder_ptr' parameter is NULL or (long *)-1
  847.         then no remainder will be returned.
  848.  
  849.     Return value:
  850.         pointer to the quotient
  851.  
  852. **********************************************************/
  853. wide *WideWideDivide
  854. (
  855.     wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  856.     long     divisor,            /* in:      value to divide by */
  857.     long    *remainder_ptr        /* out:     the remainder of the division */
  858. )
  859. {
  860.     long    remainder;
  861.  
  862.  
  863.     /* initialize Wide library if not already done */
  864.     if( !gWide_Initialized ) WideInit();
  865.  
  866.     /* IF dividing by zero */
  867.     if( divisor == 0 )
  868.     {
  869.         remainder = gxNegativeInfinity;
  870.  
  871.         /* IF dividend is negative */
  872.         if( (dividend_ptr->hi < 0) )
  873.         {
  874.             dividend_ptr->hi = gxNegativeInfinity;
  875.             dividend_ptr->lo = 0;
  876.         }
  877.         /* ELSE dividend is positive */
  878.         else
  879.         {
  880.             dividend_ptr->hi = gxPositiveInfinity;
  881.             dividend_ptr->lo = ~0;
  882.         }
  883.     }
  884.     /* ELSE overflow is not possible */
  885.     else
  886.     {
  887.         /* do the divide */
  888.         Wide_DivideS( dividend_ptr, divisor, &remainder );
  889.     }
  890.  
  891.  
  892.     /* IF the user wants a remainder */
  893.     if( (remainder_ptr != NULL) &&
  894.         (remainder_ptr != (long *) -1) )
  895.     {
  896.         *remainder_ptr = remainder;
  897.     }
  898.  
  899.     return( dividend_ptr );
  900. }
  901.  
  902.  
  903.  
  904. /**********************************************************
  905.  
  906.     Wide_DivS64 - internal routine
  907.  
  908.     Description:
  909.         A 680x0 assembly language routine that performs a
  910.         signed 64 bit division by using the DIVS.L instruction.
  911.  
  912.         The 64 bit DIVS.L instruction is only available on the
  913.         68020 to 68040 processors.
  914.  
  915.     Return value:
  916.         32 bit quotient
  917.  
  918. **********************************************************/
  919. ASM_FUNC_HEAD static long Wide_DivS64
  920. (
  921.     const wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  922.     long         divisor,            /* in:      value to divide by */
  923.     long        *remainder_ptr,        /* out:     the remainder of the division */
  924.     short        *overflow_ptr        /* out:     flag indicating if overflow occured */
  925. )
  926. {
  927. #define DIVIDEND_PTR   8
  928. #define DIVISOR       12
  929. #define REMAINDER_PTR 16
  930. #define OVERFLOW_PTR  20
  931.  
  932. ASM_BEGIN
  933.         MOVE.L  D2,-(SP)
  934.         MOVEQ.L    #1,D2                    // assume there is overflow
  935.         MOVE.L  DIVIDEND_PTR(A6),A0     // A0 -> the dividend
  936.         MOVE.L    WIDE_LO(A0),D0            //
  937.         MOVE.L    WIDE_HI(A0),D1            // D1-D0 = 64 bit dividend
  938.         DC.W    0x4C6E,0x0C01,0x000C    // DIVS.L divisor(A6),D1-D0  (64bit signed divide)
  939.         BVS        @divcont                // IF VS, we're overflowed
  940.         CLR.W    D2                        // ELSE, clear the overflow flag
  941. @divcont:
  942.         MOVE.L    REMAINDER_PTR(A6),A0    // output remainder
  943.         MOVE.L    D1,(A0)                    //
  944.         MOVE.L    OVERFLOW_PTR(A6),A0        // output overflow flag
  945.         MOVE.W    D2,(A0)                    //
  946.         MOVE.L  (SP)+,D2
  947. ASM_END
  948. ASM_FUNC_TAIL
  949. }
  950.  
  951.  
  952.  
  953. /**********************************************************
  954.  
  955.     WideDivide - (gx) Divide 32 bit int into 64 bit int with a 32 bit result
  956.  
  957.     Description:
  958.         This routine will divide a signed 32 bit integer into
  959.         a signed 64 bit integer and return a signed 32 bit quotient
  960.         and a 32 bit remainder.
  961.  
  962.         Since the return value is a 32 bit integer, overflow is possible.
  963.         If a positive overflow occurs, the return value will be gxPositiveInfinity
  964.         If a negative overflow occurs, the return value will be gxNegativeInfinity
  965.         In both cases *remainder_ptr will be set to gxNegativeInfinity.
  966.  
  967.         If a NULL pointer is passed for the 'remainder_ptr' parameter
  968.         then no remainder will be returned.
  969.  
  970.         If the pointer passed to 'remainder_ptr' is (long *)-1
  971.         then no remainder will be returned but in the case of an
  972.         overflow gxNegativeInfinity will be the return value.
  973.  
  974.     Return value:
  975.         quotient (the integer result of the division)
  976.         or
  977.         gxNegativeInfinity if negative overflow
  978.         or
  979.         gxPositiveInfinity if positive overflow
  980.  
  981. **********************************************************/
  982. long WideDivide
  983. (
  984.     const wide *dividend_ptr,    /* in:  64 bits to be divided */
  985.     long        divisor,        /* in:  value to divide by */
  986.     long       *remainder_ptr    /* out: the remainder of the division */
  987. )
  988. {
  989.     long    rv;
  990.     long    remainder;
  991.     wide    work;
  992.     short    overflow;
  993.  
  994.  
  995.     /* initialize Wide library if not already done */
  996.     if( !gWide_Initialized ) WideInit();
  997.  
  998.     /* IF not dividing by zero */
  999.     if( divisor != 0 )
  1000.     {
  1001.         /* IF the 68k 64bit divide instruction is not available */
  1002.         if( !gWide_64instr )
  1003.         {
  1004.             /* use a software subroutine for the division */
  1005.             work = *dividend_ptr;
  1006.             Wide_DivideS( &work, divisor, &remainder );
  1007.             rv = work.lo;
  1008.  
  1009.             /* determine if result overflowed a long */
  1010.             overflow = (work.hi != 0) && (work.hi != -1);
  1011.         }
  1012.         /* ELSE the 64bit division instruction is available */
  1013.         else
  1014.         {
  1015.             /* use an assembly language instruction to do the division */
  1016.             rv = Wide_DivS64( dividend_ptr, divisor, &remainder, &overflow );
  1017.         }
  1018.  
  1019.  
  1020.         /* IF the user wants a remainder */
  1021.         if( (remainder_ptr != NULL) &&
  1022.             (remainder_ptr != (long *) -1) )
  1023.         {
  1024.             *remainder_ptr = remainder;
  1025.         }
  1026.     }
  1027.  
  1028.  
  1029.     /* IF there was an overflow */
  1030.     if( overflow )
  1031.     {
  1032.         /* IF user wants a single overflow indication in the return value */
  1033.         if( remainder_ptr == (long *) -1 )
  1034.         {
  1035.             rv = gxNegativeInfinity;
  1036.         }
  1037.         else
  1038.         {
  1039.             /* IF there is a remainder pointer */
  1040.             if( remainder_ptr != NULL )
  1041.             {
  1042.                 *remainder_ptr = gxNegativeInfinity;
  1043.             }
  1044.  
  1045.             /* set overflow return value based on sign of the result */
  1046.             if( (dividend_ptr->hi & LONG_SIGN_BIT) ^ (divisor & LONG_SIGN_BIT) )
  1047.             {
  1048.                 rv = gxNegativeInfinity;
  1049.             }
  1050.             else
  1051.             {
  1052.                 rv = gxPositiveInfinity;
  1053.             }
  1054.         }
  1055.     }
  1056.  
  1057.     return( rv );
  1058. }
  1059.  
  1060.  
  1061.  
  1062. /**********************************************************
  1063.  
  1064.     Wide_MulS64 - internal routine
  1065.  
  1066.     Description:
  1067.         A 680x0 assembly language routine that performs a
  1068.         signed 64 bit division by using the MULS.L instruction.
  1069.  
  1070.         The 64 bit MULS.L instruction is only available on the
  1071.         68020 to 68040 processors.
  1072.  
  1073.     Return value:
  1074.         none
  1075.  
  1076. **********************************************************/
  1077. ASM_FUNC_HEAD static void Wide_MulS64
  1078. (
  1079.     long    multiplicand,        /* in:  first value to multiply */
  1080.     long    multiplier,            /* in:  second value to multiply */
  1081.     wide   *out_ptr                /* out: 64 bits to be assigned */
  1082. )
  1083. {
  1084. #define MULTIPLICAND   8
  1085. #define MULTIPLIER    12
  1086. #define OUT_PTR       16
  1087.  
  1088. ASM_BEGIN
  1089.         MOVE.L  MULTIPLICAND(A6),D0     //
  1090.         DC.W    0x4C2E,0x0C01,0x000C    // MULS.L multiplier(A6),D1-D0; 64bit signed multiply
  1091.         MOVE.L  OUT_PTR(A6),A0          //
  1092.         MOVE.L  D0,WIDE_LO(A0)          // WIDE_LO defined earlier
  1093.         MOVE.L  D1,WIDE_HI(A0)          // WIDE_HI defined earlier
  1094. ASM_END
  1095. ASM_FUNC_TAIL
  1096. }
  1097.  
  1098.  
  1099.  
  1100. /**********************************************************
  1101.  
  1102.     WideMultiply - (gx) Multiply two 32 bits ints for a 64 bit result
  1103.  
  1104.     Description:
  1105.         This routine will multiply two signed 32 bit values
  1106.         and assign the result to a signed 64 bit integer
  1107.  
  1108.     Return value:
  1109.         the target pointer passed into this function
  1110.  
  1111. **********************************************************/
  1112. wide *WideMultiply
  1113. (
  1114.     long    multiplicand,        /* in:  first value to multiply */
  1115.     long    multiplier,            /* in:  second value to multiply */
  1116.     wide   *target_ptr            /* out: 64 bits to be assigned */
  1117. )
  1118. {
  1119.     /* initialize Wide library if not already done */
  1120.     if( !gWide_Initialized ) WideInit();
  1121.  
  1122.     /* IF the 64bit multiply instruction is available */
  1123.     if( gWide_64instr )
  1124.     {
  1125.         /* execute the assembly language instruction MULS.L */
  1126.         Wide_MulS64( multiplicand, multiplier, target_ptr );
  1127.     }
  1128.     else
  1129.     {
  1130.         /* call toolbox to perform the multiply */
  1131.         LongMul( multiplicand, multiplier, (Int64Bit *) target_ptr );
  1132.     }
  1133.  
  1134.     return( target_ptr );
  1135. }
  1136.  
  1137.  
  1138.  
  1139.  
  1140. /**********************************************************
  1141.  
  1142.     WideNegate - (gx) Negative value of a 64 bit int
  1143.  
  1144.     Description:
  1145.         This routine will calculate the negative value of
  1146.         a signed 64 bit integer
  1147.  
  1148.     Return value:
  1149.         the target pointer passed into this function
  1150.  
  1151. **********************************************************/
  1152. wide *WideNegate
  1153. (
  1154.     wide    *target_ptr     /* in/out: 64 bits to be negated */
  1155. )
  1156. {
  1157. register long           accum_hi;
  1158. register unsigned long accum_lo;
  1159. register wide *destp;
  1160.  
  1161.  
  1162.     /* initialize Wide library if not already done */
  1163.     if( !gWide_Initialized ) WideInit();
  1164.  
  1165.     destp = target_ptr;
  1166.     accum_lo = destp->lo;
  1167.     accum_hi = destp->hi;
  1168.  
  1169.     /* 1's complement */
  1170.     accum_lo = ~accum_lo;
  1171.     accum_hi = ~accum_hi;
  1172.  
  1173.     /* 2's complement */
  1174.     accum_lo += 1;
  1175.     if( accum_lo == 0 )
  1176.     {
  1177.         /* propagate the carry */
  1178.         accum_hi += 1;
  1179.     }
  1180.  
  1181.     destp->hi = accum_hi;
  1182.     destp->lo = accum_lo;
  1183.  
  1184.     return( destp );
  1185. }
  1186.  
  1187.  
  1188.  
  1189.  
  1190. /**********************************************************
  1191.  
  1192.     WideShift() - (gx) Shift a 64 bit number and round up
  1193.  
  1194.     Description:
  1195.         This routine will perform an arithmetic shift on a
  1196.         64 bit number with rounding.
  1197.  
  1198.         The shift is be similar to the WideBitShift() routine
  1199.         except that the result is rounded by adding half and
  1200.         truncating the remainder.
  1201.  
  1202.         (eg) Performing a shift of +3 on a value of 0x0C will
  1203.              return 2 with WideShift() and 1 with WideBitShift()
  1204.  
  1205.     Return value:
  1206.         the target pointer passed into this function
  1207.  
  1208. **********************************************************/
  1209. wide *WideShift
  1210. (
  1211.     wide    *target_ptr,    /* in/out: 64 bits to be shifted */
  1212.     short       amount      /* in:     shift amount (+ right, - left) */
  1213. )
  1214. {
  1215.     long    shifted_out;
  1216.  
  1217.  
  1218.     /* initialize Wide library if not already done */
  1219.     if( !gWide_Initialized ) WideInit();
  1220.  
  1221.     /* IF shifting to the left */
  1222.     if( amount <= 0 )
  1223.     {
  1224.         /* perform an arithmetic shift */
  1225.         WideBitShift( target_ptr, amount );
  1226.     }
  1227.     /* ELSE shifting to the right */
  1228.     else
  1229.     {
  1230.         /* IF bit shifted out is in .lo */
  1231.         if( amount <= 32 )
  1232.         {
  1233.             shifted_out = target_ptr->lo & (1L << (amount-1));
  1234.         }
  1235.         /* ELSE IF bit shifted out is in .hi */
  1236.         else if( amount <= 64 )
  1237.         {
  1238.             shifted_out = target_ptr->hi & (1L << (amount-33));
  1239.         }
  1240.         else
  1241.         {
  1242.             shifted_out = 0;
  1243.         }
  1244.     
  1245.         /* perform an arithmetic shift */
  1246.         WideBitShift( target_ptr, amount );
  1247.     
  1248.         /* IF there was a bit shifted out */
  1249.         if( shifted_out != 0 )
  1250.         {
  1251.             /* add the bit that was shifted out */
  1252.             WideAdd32( target_ptr, 1 );
  1253.         }
  1254.     }
  1255.  
  1256.     return( target_ptr );
  1257. }
  1258.  
  1259.  
  1260.  
  1261. /**********************************************************
  1262.  
  1263.     Wide_FromExtended - internal routine
  1264.  
  1265.     Description:
  1266.         An internal routine that converts an unsigned 'extended'
  1267.         value to an unsigned 'wide' value.
  1268.  
  1269.     Return value:
  1270.         none
  1271.  
  1272. **********************************************************/
  1273. static void Wide_FromExtended
  1274. (
  1275.         wide        *target_ptr,    /* out: unsigned 64 bits */
  1276.   const Extended_80    *source_ptr     /* in:  unsigned extended number to convert */
  1277. )
  1278. {
  1279. register short           shift;
  1280. register unsigned long hi;
  1281. register unsigned long lo;
  1282. const struct _extended80 *inp = (struct _extended80 *) source_ptr;
  1283.  
  1284.  
  1285.     /* IF bits should be right justified */
  1286.     shift =  63 - (inp->exp - 0x3FFF);
  1287.     if( (shift > 0) && (shift < 64) )
  1288.     {
  1289.         /* get copy of 'extended' number */
  1290.         hi = (*(long *) &inp->man[0]);
  1291.         lo = (*(long *) &inp->man[2]);
  1292.  
  1293.         /* perform a logical shift to the right */
  1294.         while( shift-- > 0 )
  1295.         {
  1296.             lo >>= 1;
  1297.             if( hi & 1 )
  1298.                 lo |= LONG_SIGN_BIT;
  1299.             hi >>= 1;
  1300.         }
  1301.     }
  1302.     else
  1303.     {
  1304.         hi = 0;
  1305.         lo = 0;
  1306.     }
  1307.  
  1308.     /* output the result */
  1309.     target_ptr->hi = hi;
  1310.     target_ptr->lo = lo;
  1311. }
  1312.  
  1313.  
  1314.  
  1315. /**********************************************************
  1316.  
  1317.     WideSquareRoot - (gx) return 32 bit square root of an unsigned 64 bit number
  1318.  
  1319.     Description:
  1320.         This routine will calculate the unsigned 32 bit
  1321.         square root of an unsigned 64 bit number.
  1322.  
  1323.         Since the source number must be unsigned it's range
  1324.         can be from 0 to 2^64 - 1
  1325.  
  1326.         Overflow of the return value is not possible.
  1327.  
  1328.     Return value:
  1329.         32 bit unsigned square root
  1330.  
  1331. **********************************************************/
  1332. unsigned long WideSquareRoot
  1333. (
  1334.     const wide  *source_ptr        /* in: unsigned value to take the square root of */
  1335. )
  1336. {
  1337.     wide         work_int;
  1338.     Extended_80  ext_number;
  1339.  
  1340.  
  1341.     /* initialize Wide library if not already done */
  1342.     if( !gWide_Initialized ) WideInit();
  1343.  
  1344.     /* convert 'wide' number to 'extended' format */
  1345.     Wide_ToExtended( &ext_number, source_ptr );
  1346.  
  1347.     /* calculate the square root of a positive number using SANE */
  1348.  
  1349.     /* IF compiling with MetroWorks, the parameter of sqrt() is a
  1350.        pointer instead of a value as defined in PowerPC Numerics */
  1351. #ifdef __MWERKS__
  1352.     Sqrt( &ext_number );
  1353. #else
  1354.     ext_number = sqrt( ext_number );
  1355. #endif
  1356.  
  1357.     /* convert 'extended' format to 'wide' number */
  1358.     Wide_FromExtended( &work_int, &ext_number );
  1359.  
  1360.     /* ok to ignore work_int.hi because its always zero */
  1361.     return( work_int.lo );
  1362. }
  1363.  
  1364.  
  1365.  
  1366.  
  1367. /**********************************************************
  1368.  
  1369.     WideSubtract - (gx) Subtract a 64 bits int from a 64 bit int
  1370.  
  1371.     Description:
  1372.         This routine will subtract a signed 64 bit integer
  1373.         from a signed 64 bit integer
  1374.  
  1375.     Return value:
  1376.         the target pointer passed into this function
  1377.  
  1378. **********************************************************/
  1379. wide *WideSubtract
  1380. (
  1381.           wide  *target_ptr,    /* out: 64 bits to be subtracted from */
  1382.     const wide  *source_ptr        /* in:  subtraction value */
  1383. )
  1384. {
  1385. register unsigned long accum_lo;
  1386. register long           accum_hi;
  1387. register wide *destp;
  1388.  
  1389.  
  1390.     /* initialize Wide library if not already done */
  1391.     if( !gWide_Initialized ) WideInit();
  1392.  
  1393.     /* perform a partial subtract */
  1394.     destp = target_ptr;
  1395.     accum_lo = destp->lo - source_ptr->lo;
  1396.     accum_hi = destp->hi - source_ptr->hi;
  1397.  
  1398.     /* IF the low long has overflowed */
  1399.     if( destp->lo < source_ptr->lo )
  1400.     {
  1401.         /* propagate the borrow */
  1402.         accum_hi -= 1;
  1403.     }
  1404.  
  1405.     destp->hi = accum_hi;
  1406.     destp->lo = accum_lo;
  1407.  
  1408.     return( destp );
  1409. }
  1410.  
  1411. #endif
  1412.  
  1413. #endif